/*
 * StabSolver.h
 *
 *  Created on: Sep 18, 2011
 *      Author: correa
 */

#ifndef STABSOLVER_H_
#define STABSOLVER_H_

#include <string>
#include "Graph.h"
using namespace std;

class StabModel {
protected:
	Graph *			g;
	int 			n;
	int 			m;
	int 			ccnt_v;
	int 			rcnt_v;
	int 			nzcnt_v;
	int				firstcol_v;
	char ** 		rowname_v;
	char * 			rnamestore_v;
	char ** 		colname_v;
	char * 			cnamestore_v;
	int 			storespace_v;
	int *  			rmatbeg_v;
	int *  			rmatind_v;
	double *  		rmatval_v;
	char * 			sense_v;
	double * 		rhs_v;
	char * 			type_v;
	char *			sostype_v;
	int *			cliquerank_v;

public:
	StabModel(Graph * g) : g(g), n(g->nverts()), m(g->nedges() >> 1), ccnt_v(0), rcnt_v(0), nzcnt_v(0), firstcol_v(0),
	rowname_v(NULL), rnamestore_v(NULL), colname_v(NULL), cnamestore_v(NULL),
	rmatbeg_v(NULL), rmatind_v(NULL), rmatval_v(NULL), sense_v(NULL), rhs_v(NULL), type_v(NULL), sostype_v(NULL), cliquerank_v(NULL) {};
	~StabModel();
	Graph * 	graph() { return g; };
	int 		ccnt() { return ccnt_v; };
	int 		rcnt() { return rcnt_v; };
	int 		nzcnt() { return nzcnt_v; };
	char **		rowname();
	void		delrowname();
	const char *rnamestore(int * spc);
	void 		delrnamestore();
	char **		colname();
	void		delcolname();
	const char *cnamestore(int * spc);
	void 		delcnamestore();
	const int *	rmatbeg();
	void		delrmatbeg();
	const char *sense();
	void 		delsense();
	const double *rhs();
	void		delrhs();
	const char *type();
	void 		deltype();
	const char *sostype();
	void		delsostype();
	const int * rmatind();
	void  		delrmatind();
	const double *rmatval();
	void		delrmatval();
	const int * cliquerank();
	void  		delcliquerank();
	void		delall();
};

class StabModeler : public StabModel {
	template <class S, class G>	friend class ModelerFactory;

	StabModeler(Graph * g);
	StabModeler(Graph * g, int col, const char * prefix);
	StabModeler(Graph * g, int * cr);
	StabModeler(Graph * g, int col, const char * prefix, int * cr);
protected:
	char  	prefix[30];
	int		ub;

public:
	~StabModeler();
	virtual int stabcols();
	virtual int edgerows();
	virtual int isolatedrows();
	virtual int cliquerows(int * nc);
	virtual int edgesymcuts();
	virtual int scalerows(int begin, int end, int col, double coeff);
	virtual int scalerows(int begin, int end, double rhs);
	virtual int objective(Weight<double> * w);
	virtual int startingpoint(int * S);
};

class RepModeler : public StabModel {
	template <class S, class G> friend class ModelerFactory;

protected:
	char 			prefix[30];
	int				nreps_v;
	int *			rp_v;
	int *			rd_v;
	int *			Rarray;
	int ** 			R;
	Graph **		grep;
	int *			firstrepcol;
	StabModeler **	mrep;

	void init(Graph * g, int col, const char * prefix);
	RepModeler(Graph * g, bool dummy);
	RepModeler(Graph * g);
	RepModeler(Graph * g, int col, const char * prefix);
	RepModeler(Graph * g, int * cr);
	RepModeler(Graph * g, int col, const char * prefix, int * cr);
public:
	~RepModeler();

	virtual StabModeler *	submodeler(int rep, int firstcol);
	virtual int				nreps();
	virtual const int *		rp(int i, int *nrp);
	virtual const int *		rd(int i, int *nrd);
	int 					repcol(int rep);
	int 					disjointrows();
	int 					repedgesymcuts(int i);
	int 					nrepsrow(int k);
	int 					objective(Weight<double> * w);
	int						repvar(int rep, char lb, double bd);
};

class ARepModeler : public RepModeler {
	template <class S, class G> friend class ModelerFactory;

	bool * ordered;
	ARepModeler(Graph * g);
	ARepModeler(Graph * g, int col, const char * prefix);
	ARepModeler(Graph * g, int * cr);
	ARepModeler(Graph * g, int col, const char * prefix, int * cr);
public:
	~ARepModeler();
	virtual const int *		rd(int i, int *nrd);
};

template <class S, class G>
class ModelerFactory {
public:
	ModelerFactory() {};
    // Static class to create objects
    // Change is required only in this function to create a new object type
	static S * create(G * g) { return new S(g); };
	static S * create(G * g, int col, const char * prefix) { return new S(g, col, prefix); };
	static S * create(G * g, int * cr) { return new S(g, cr); };
	static S * create(G * g, int col, const char * prefix, int * cr) { return new S(g, col, prefix, cr); };
};

class StabSolver {
protected:
	Weight<double> * 	w;
	StabSolver() {};
public:
	virtual ~StabSolver() {};
	virtual int solveByEnumeration() = 0;
	virtual int getBest(double * val) = 0;
	virtual int getNodes(int * nnd) = 0;

    // Static class to create objects
    // Change is required only in this function to create a new object type
    static StabSolver * create(string form, Graph * g);
    template <class M, class G>
    static StabSolver * create(Graph * g, ModelerFactory<M,G> * fm);
    template <class M, class G>
    static StabSolver * create(string relax, Graph * g, ModelerFactory<M,G> * fm, int k);
};

#endif /* STABSOLVER_H_ */
